
package Individual;

import Individual.*;
import Loader.BufferedData;
import Settings.Settings;


public class ReproductionFunctions {

    public static void reproduction( FitnessFunctions fitnessFunctions,
                                     Individual[] individuals,
                                     BufferedData bd
                                   ) {

        if(individuals == null || individuals.length == 0)
            return;

        //fitnesses individuals
        float fitnesses[] = new float[individuals.length];
        float fitnessAll = 0;

        //cumulative propability
        float[] cumulativePropability = new float[individuals.length];

        //new population
        Individual[] individualsNew = new Individual[individuals.length];
        
        for(int i = 0; i < individuals.length; ++i) {

            fitnesses[i] = fitnessFunctions.fitness( individuals[i],
                                                     true);
            fitnessAll += fitnesses[i];
            
        }
/*
        if( Settings.PRINT_DEBBUG )
                System.out.println(String.format("Average fitness: %2.7f",
                                                 (fitnessAll/individuals.length)
                                                )
                                  );
*/
        //create new random chromosome and compare with randomly selected
        if( Settings.EXTERNAL_REPRODUCTION ) {
            int noIndividual = (int) (Math.random() * individuals.length);
            int numOfCluster = individuals[noIndividual].numOfClusters;
            int numOfFeatures = individuals[noIndividual].numOfFeatures;
            int numOfBitsPerValue = individuals[noIndividual].numOfBitsPerValue;
            Individual individual = new Individual( numOfCluster,
                                                    numOfFeatures,
                                                    numOfBitsPerValue,
                                                    bd
                                                  );

            for(int c = 0; c < numOfCluster; ++c)
                for(int f = 0; f < numOfFeatures; ++f)
                    for(int b = 0; b < numOfBitsPerValue; ++b) {
                        boolean bitVal = Math.random()<0.5;
                        individual.chromosome.get(c).get(f).set( b, bitVal );
                    }

            float fitIndividualRandom = fitnessFunctions.fitness( individual,
                                                                  true
                                                                );

            //randomly chromosome is better
            if( fitIndividualRandom > fitnesses[noIndividual]) {

                //delete individuals[noIndividual] and insert new
                individuals[noIndividual]=individual;//replace

            }
            
        } //end if(external)


        //reproduction
        cumulativePropability[0] = fitnesses[0] / fitnessAll;

        for(int i = 1; i < individuals.length; ++i) {
            cumulativePropability[i] = cumulativePropability[ i-1 ] +
                                       fitnesses[ i ] / fitnessAll;
        }

        //roulette
        for(int i = 0; i < individuals.length; ++i) {

            float random = (float) Math.random();

            if( random <= cumulativePropability[0] ) {

                individualsNew[i] = individuals[0];

            } else {

                boolean found = false;

                for(int j = 1; j < individuals.length && !found; ++j)
                    if( random > cumulativePropability[j-1] &&
                        random <= cumulativePropability[j]
                      ) {

                        individualsNew[i] = individuals[j];
                        found = true;
                    }

                if( !found )
                    individualsNew[i] = individuals[ individuals.length - 1 ];

            }

        }

        individuals = individualsNew;

    }

}
